package com.polaris.live.ui.live.widget

import android.content.Context
import android.graphics.Rect
import android.text.InputFilter
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.util.AttributeSet
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewTreeObserver
import android.view.inputmethod.InputMethodManager
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.blankj.utilcode.util.ColorUtils
import com.blankj.utilcode.util.KeyboardUtils
import com.blankj.utilcode.util.StringUtils
import com.blankj.utilcode.util.Utils
import com.polaris.live.R
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.ext.autoDp
import com.polaris.live.common.ext.dp
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.common.util.AppCodeUtils
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.databinding.WidgetLiveEditBinding
import com.polaris.live.im.sfs.bean.live.AtUser
import com.polaris.live.im.sfs.bean.live.CallPublicScreenMessage
import com.polaris.live.im.sfs.bean.live.LivePublicScreenMessage
import com.polaris.live.im.sfs.bean.live.LiveRoomInfo
import com.polaris.live.net.userService
import com.polaris.live.resp.back_resp.CallVo
import com.polaris.live.resp.back_resp.UserBackpackBarrageNumberResp
import com.polaris.live.translation.R.string
import com.polaris.live.ui.live.widget.listener.OnSendCallPublicMessageListener
import com.polaris.live.ui.live.widget.listener.OnSendPartyMessageListener
import com.polaris.live.ui.live.widget.listener.OnSendPublicMessageListener
import com.polaris.live.utils.viewscope.autoDisposeScope
import kotlinx.coroutines.launch

/**
 * LiveEditView
 *
 * @author Created by lucas on 2023/11/7 15:50
 */
abstract class AbstractLiveEditView(context: Context, attributeSet: AttributeSet) :
    LinearLayout(context, attributeSet) {

    val mBinding = WidgetLiveEditBinding.inflate(LayoutInflater.from(context), this)

    private var mLastKeyboardHeight: Int = -1
    private val mRect = Rect()

    //@功能的集合发的时候要转成json
    protected val mTellList = mutableListOf<AtUser>()

    private var mKeyboardListerState: Boolean = true

    private var mBarrage: UserBackpackBarrageNumberResp? = null //弹幕数据

    var openBarrage: Boolean = false //开启弹幕

    init {
        orientation = HORIZONTAL
        gravity = Gravity.CENTER
        visibility = GONE
        setBackgroundResource(R.color.white)
        //注册软键盘监听
        KeyboardUtils.registerSoftInputChangedListener(ViewUtils.requireWindow(context)) {
            if (!mKeyboardListerState) {
                return@registerSoftInputChangedListener
            }

            if (it <= 0) {
                visibility = GONE
                mTellList.clear()
                mBinding.etEdit.setText("")
            } else {
                visibility = VISIBLE
                val length = mBinding.etEdit.text?.length
                if (length != null && length != 0) {
                    mBinding.etEdit.setSelection(length)
                }
            }
        }
        if (AppCodeUtils.isAR()) {
            mBinding.imgBarrage.scaleX = -1f
            mBinding.tvSend.scaleX = -1f
            mBinding.etEdit.setPadding(0, 6.autoDp, 12.autoDp, 6.autoDp)
        } else {
            mBinding.etEdit.setPadding(12.autoDp, 6.autoDp, 0, 6.autoDp)
        }

        mBinding.imgWhat.setOnClickListener {
            hideKeyboard()
            clickBarrage()
        }
        mBinding.imgBarrage.setOnClickListener {
            if (openBarrage) {
                mBinding.imgBarrage.setImageResource(R.drawable.vip_barrage_close)
                mBinding.imgWhat.visibility = View.GONE
                mBinding.etEdit.hint = StringUtils.getString(string.live_hide_text)
                if (AppCodeUtils.isAR()) {
                    mBinding.etEdit.setPadding(0, 6.autoDp, 12.autoDp, 6.autoDp)
                } else {
                    mBinding.etEdit.setPadding(12.autoDp, 6.autoDp, 0, 6.autoDp)
                }
                mBinding.etEdit.filters = arrayOf(InputFilter.LengthFilter(140))
            } else {
                mBinding.imgBarrage.setImageResource(R.drawable.vip_barrage_open)
                mBinding.imgWhat.visibility = View.VISIBLE
                if (AppCodeUtils.isAR()) {
                    mBinding.etEdit.setPadding(36.autoDp, 6.autoDp, 12.autoDp, 6.autoDp)
                } else {
                    mBinding.etEdit.setPadding(12.autoDp, 6.autoDp, 36.autoDp, 6.autoDp)
                }
                mBarrage?.let { bean ->
                    val hintText = if (bean.number > 0) {
                        buildHintTextWithNumber(bean.number)
                    } else {
                        if (!bean.free) {
                            buildHintTextWithCoin(bean.coin)
                        } else {
                            StringUtils.getString(string.live_hide_text)
                        }
                    }
                    mBinding.etEdit.hint = hintText
                } ?: run {
                    mBinding.etEdit.hint = StringUtils.getString(string.live_hide_text)
                }
                mBinding.etEdit.filters = arrayOf(InputFilter.LengthFilter(50))

            }
            openBarrage = !openBarrage
        }

    }

    private fun buildHintTextWithNumber(number: Long): SpannableString {
        val countText = "$number"
        val contextText = StringUtils.getString(string.barrage_cards_sheets, countText)
        val hintText = SpannableString(contextText)
        val index = contextText.indexOf(countText)
        hintText.setSpan(
            ForegroundColorSpan(ColorUtils.getColor(R.color.color_ffa100)),
            index,
            index + countText.length,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )

        return hintText
    }

    private fun buildHintTextWithCoin(coin: Long): SpannableString {
        val replaceText = "$%$"
        val countText = "$coin"
        val contextText = StringUtils.getString(string.send_bullet_comments, "$countText $replaceText")
        val hintText = SpannableString(contextText)

        val index = contextText.indexOf(replaceText)
        val drawable = ContextCompat.getDrawable(context, R.drawable.diamond)
        drawable?.let {
            drawable.setBounds(0, 0, 13.autoDp, 12.autoDp)
            val imageSpan = ImageSpan(drawable, ImageSpan.ALIGN_BASELINE)
            hintText.setSpan(
                imageSpan,
                index,
                index + replaceText.length,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
        return hintText
    }

    fun closeBarrage() {
        openBarrage = false
        mBinding.imgBarrage.setImageResource(R.drawable.vip_barrage_close)
        mBinding.imgWhat.visibility = View.GONE
        mBinding.etEdit.hint = StringUtils.getString(string.live_hide_text)
        if (AppCodeUtils.isAR()) {
            mBinding.etEdit.setPadding(0, 6.autoDp, 12.autoDp, 6.autoDp)
        } else {
            mBinding.etEdit.setPadding(12.autoDp, 6.autoDp, 0, 6.autoDp)
        }
        mBinding.etEdit.filters = arrayOf(InputFilter.LengthFilter(140))
    }

    abstract fun reset()

    fun atUser(userId: Long, nickName: String) {
        mBinding.tvSend.performClick()
        mBinding.etEdit.setText("@ $nickName ")
        mTellList.add(AtUser(userId, nickName))

        showKeyboard()
    }

    fun showKeyboard() {
        visibility = View.VISIBLE
        requestFocus()
        val imm =
            Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.showSoftInput(mBinding.etEdit, InputMethodManager.SHOW_IMPLICIT)
    }

    fun hideKeyboard() {
        KeyboardUtils.hideSoftInput(ViewUtils.requireWindow(context))
    }

    private val mOnGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
        rootView.getWindowVisibleDisplayFrame(mRect)
        val keyboardHeight = rootView.height - mRect.bottom

        if (mLastKeyboardHeight != keyboardHeight) {
            ViewUtils.setMargin(
                this,
                bottomMargin = keyboardHeight - 1.dp
            )

            mLastKeyboardHeight = keyboardHeight
        }
    }

    fun setKeyboardListerState(keyboardListerState: Boolean) {
        mKeyboardListerState = keyboardListerState
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        mBinding.imgBarrage.visibility = if (showBarrage()) VISIBLE else GONE
        rootView.viewTreeObserver.addOnGlobalLayoutListener(mOnGlobalLayoutListener)
        if (showBarrage()) {
            getBarrageData()
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()

        rootView.viewTreeObserver?.removeOnGlobalLayoutListener(mOnGlobalLayoutListener)
    }

    /**
     * 是否显示弹幕图标
     */
    abstract fun showBarrage(): Boolean

    /**
     * 点击弹幕what
     */
    abstract fun clickBarrage()

    /**
     * 获取弹幕信息
     */
    private fun getBarrageData() {
        autoDisposeScope.launch {
            val data = userService.getBarrageNumber()
            if (data.isSuccess()) {
                mBarrage = data.result
            }

        }
    }

    fun upBarrage(mBarrage: UserBackpackBarrageNumberResp) {
        this.mBarrage = mBarrage
    }

}

class PartyEditView(context: Context, attributeSet: AttributeSet) :
    AbstractLiveEditView(context, attributeSet) {

    private var mLiveInfo: LiveRoomInfo? = null

    private var mOnSendPartyMessageListener: OnSendPartyMessageListener? = null

    init {
        //发送公屏消息
        mBinding.tvSend.setOnSingleClickListener {
            val content = mBinding.etEdit.text?.toString()
            if (content.isNullOrEmpty()) {
                return@setOnSingleClickListener
            }

            if (content.isBlank()) {
                ToastGravity.showGravity(context.getString(string.content_noncompliance))
                return@setOnSingleClickListener
            }
            if (openBarrage && content.length > 50) {
                ToastGravity.showGravity(context.getString(string.barrage_content_limit))
                return@setOnSingleClickListener
            }

            var replace: String = if (openBarrage) content.replace("\n", "") else content
            val finalTellList = mutableListOf<AtUser>()
            mTellList.forEach {
                if (replace.contains("@ ${it.nickname}")) {
                    replace = replace.replace("@ ${it.nickname}", "")
                    finalTellList.add(it)
                }
            }

            val recipient = mLiveInfo?.userId
            val liveId = mLiveInfo?.liveId

            if (recipient != null && liveId != null) {
                try {
                    val callPublicScreenMessage = LivePublicScreenMessage(
                        content = replace,
                        anchorId = recipient,
                        liveId = liveId,
                        atUsers = JsonUtils.toJson(finalTellList),
                        type = if (openBarrage) 1 else 0
                    )
                    mOnSendPartyMessageListener?.onSendPublicMessage(callPublicScreenMessage)
                    mBinding.etEdit.setText("")
                    KeyboardUtils.hideSoftInput(ViewUtils.requireWindow(context))
                    mTellList.clear()
                } catch (e: Throwable) {
                    ToastGravity.showGravity(e.message)
                }
            }
        }
    }

    fun initData(liveInfo: LiveRoomInfo) {
        mLiveInfo = liveInfo
    }

    override fun reset() {
        mLiveInfo = null
    }

    override fun showBarrage() = true
    override fun clickBarrage() {
        mOnSendPartyMessageListener?.onBarrageWhat()
    }

    fun setOnSendPartyMessageListener(l: OnSendPartyMessageListener) {
        this.mOnSendPartyMessageListener = l
    }
}

class LiveEditView(context: Context, attributeSet: AttributeSet) :
    AbstractLiveEditView(context, attributeSet) {

    private var mLiveInfo: LiveRoomInfo? = null

    private var mOnSendPublicMessageListener: OnSendPublicMessageListener? = null

    init {
        //发送公屏消息
        mBinding.tvSend.setOnSingleClickListener {
            val content = mBinding.etEdit.text?.toString()
            if (content.isNullOrEmpty()) {
                return@setOnSingleClickListener
            }

            if (content.isBlank()) {
                ToastGravity.showGravity(context.getString(string.content_noncompliance))
                return@setOnSingleClickListener
            }
            if (openBarrage && content.length > 50) {
                ToastGravity.showGravity(context.getString(string.barrage_content_limit))
                return@setOnSingleClickListener
            }
            var replace: String = if (openBarrage) content.replace("\n", "") else content
            val finalTellList = mutableListOf<AtUser>()
            mTellList.forEach {
                if (replace.contains("@ ${it.nickname}")) {
                    replace = replace.replace("@ ${it.nickname}", "")
                    finalTellList.add(it)
                }
            }

            val recipient = mLiveInfo?.userId
            val liveId = mLiveInfo?.liveId

            if (recipient != null && liveId != null) {
                try {
                    val callPublicScreenMessage = LivePublicScreenMessage(
                        content = replace,
                        anchorId = recipient,
                        liveId = liveId,
                        atUsers = JsonUtils.toJson(finalTellList),
                        type = if (openBarrage) 1 else 0
                    )
                    mOnSendPublicMessageListener?.onSendPublicMessage(callPublicScreenMessage)
                    mBinding.etEdit.setText("")
                    KeyboardUtils.hideSoftInput(ViewUtils.requireWindow(context))
                    mTellList.clear()
                } catch (e: Throwable) {
                    ToastGravity.showGravity(e.message)
                }
            }
        }
    }

    fun initData(liveInfo: LiveRoomInfo) {
        mLiveInfo = liveInfo
    }

    override fun reset() {
        mLiveInfo = null
    }

    override fun showBarrage() = true
    override fun clickBarrage() {
        mOnSendPublicMessageListener?.onBarrageWhat()
    }

    fun setOnSendPublicMessageListener(l: OnSendPublicMessageListener) {
        this.mOnSendPublicMessageListener = l
    }
}

class CallEditView(context: Context, attributeSet: AttributeSet) :
    AbstractLiveEditView(context, attributeSet) {

    private var mCallInfo: CallVo? = null

    private var mOnSendPublicMessageListener: OnSendCallPublicMessageListener? = null

    init {
        //发送公屏消息
        mBinding.tvSend.setOnSingleClickListener {
            val content = mBinding.etEdit.text?.toString()
            if (content.isNullOrEmpty()) {
                return@setOnSingleClickListener
            }

            if (content.isBlank()) {
                ToastGravity.showGravity(context.getString(string.content_noncompliance))
                return@setOnSingleClickListener
            }

            val recipient = if (mCallInfo?.senderId != UserManager.getUserId()) {
                mCallInfo?.senderId
            } else {
                mCallInfo?.answerId
            }
            val callId = mCallInfo?.id

            if (recipient != null && callId != null) {
                try {
                    val callPublicScreenMessage = CallPublicScreenMessage(
                        content = content,
                        recipient = recipient,
                        callId = callId
                    )
                    mOnSendPublicMessageListener?.onSendPublicMessage(callPublicScreenMessage)
                    mBinding.etEdit.setText("")
                    KeyboardUtils.hideSoftInput(ViewUtils.requireWindow(context))
                } catch (e: Throwable) {
                    ToastGravity.showGravity(e.message)
                }
            }
        }

    }

    fun initData(callInfo: CallVo) {
        mCallInfo = callInfo
    }

    override fun reset() {
        mCallInfo = null
    }

    override fun showBarrage() = false
    override fun clickBarrage() {
    }

    fun setOnSendPublicMessageListener(l: OnSendCallPublicMessageListener) {
        this.mOnSendPublicMessageListener = l
    }
}

class LuckyBagEditView(context: Context, attributeSet: AttributeSet) :
    AbstractLiveEditView(context, attributeSet) {

    override fun reset() {

    }

    override fun showBarrage() = false
    override fun clickBarrage() {
    }
}